home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1994 November / macformat-018.iso / Utility Spectacular / Developer / Fonts Folder Tuner 1.1.• / Sources / fonts folder tuner.c next >
Encoding:
C/C++ Source or Header  |  1993-07-24  |  12.0 KB  |  492 lines  |  [TEXT/KAHL]

  1. // System 7.1 font folder patch
  2. // version 1.1
  3. // joe holt  20 july 1993
  4.  
  5. #include <GestaltEqu.h>
  6. #include <Folders.h>
  7.  
  8. static OSErr patch_system( void );
  9. OSErr DuplicateFile( FSSpecPtr source, FSSpecPtr destination );
  10.  
  11. #define k_Failed_ALRT        128
  12. #define k_progress_DLOG        129
  13. #define k_Succeeded_ALRT    130
  14.  
  15. Boolean Success( Boolean condition, int string_index );
  16.  
  17. enum {
  18.     k_failed_not_system_71 = 1,
  19.     k_failed_unknown_system,
  20.     k_failed_already_tuned,
  21.     k_failed_cant_update,
  22.     k_failed_cant_update_disk_full,
  23.     k_failed_cant_update_disk_error,
  24.     k_failed_cant_update_and_system_is_in_trash,
  25.     k_failed_cant_update_and_system_has_funny_name
  26. };
  27.  
  28.  
  29. static unsigned char *strings;
  30. static int num_strings;
  31.  
  32.  
  33. #define assert(condition) \
  34.     ( (condition) ? 1 : (assertFailed( __FILE__, __LINE__, #condition ), 0) )
  35. static void assertFailed( char *file, long line, char *condition );
  36. void assertFailed( char *file, long line, char *condition )
  37. {
  38.     unsigned char text[256];
  39.     unsigned char num[20];
  40.     char *s;
  41.     unsigned char *d;
  42.     int i;
  43.  
  44.     d = &text[1];
  45.  
  46.     i = 0;
  47.     if ( line > 1000 ) {
  48.         num[++i] = '0' + line / 1000;
  49.         line %= 1000;
  50.     }
  51.     if ( line > 100 ) {
  52.         num[++i] = '0' + line / 100;
  53.         line %= 100;
  54.     }
  55.     if ( line > 10 ) {
  56.         num[++i] = '0' + line / 10;
  57.         line %= 10;
  58.     }
  59.     num[++i] = '0' + line;
  60.     num[0] = i;
  61.  
  62.     for ( s = file; *s; ) *d++ = *s++;
  63.     for ( s = ", line "; *s; ) *d++ = *s++;
  64.     for ( i = num[0], s = (char *) &num[1]; i; --i ) *d++ = *s++;
  65.     for ( s = ": ("; *s; ) *d++ = *s++;
  66.     for ( s = condition; *s; ) *d++ = *s++;
  67.     for ( s = ") failed"; *s; ) *d++ = *s++;
  68.     text[0] = d - &text[1];
  69.  
  70.     DebugStr( text );
  71.     ExitToShell();
  72. }
  73.  
  74.  
  75. void main( void );
  76. void main( void )
  77. {
  78.     Handle h;
  79.     OSErr result;
  80.     long response;
  81.     EventRecord the_event;
  82.     int i;
  83.     DialogPtr dialog;
  84.  
  85.     MaxApplZone();
  86.     InitGraf( &thePort );
  87.     InitFonts();
  88.     InitWindows();
  89.     InitDialogs( nil );
  90.     TEInit();
  91.     InitMenus();
  92.     InitCursor();
  93.     for ( i = 5; i; --i ) OSEventAvail( 0, &the_event );                
  94.  
  95.     h = GetResource( 'STR#', 128 );
  96.     assert( h );
  97.     MoveHHi( h );
  98.     HLock( h );
  99.     num_strings = **(short **)h;
  100.     strings = (unsigned char *) StripAddress( *h + 2 );
  101.  
  102.  
  103. // quick check to make sure this is System 7.1
  104.  
  105.     result = Gestalt( gestaltSystemVersion, &response );
  106.     if ( !Success( !result && response == 0x0710, k_failed_not_system_71 ) ) return;
  107.  
  108.  
  109. // let's try patching it; put up the "please wait" dialog
  110.  
  111.     SetCursor( *GetCursor( watchCursor ) );
  112.     dialog = GetNewDialog( k_progress_DLOG, nil, (WindowPtr) -1 );
  113.     assert( dialog );
  114.     DrawDialog( dialog );
  115.  
  116.  
  117. // try the patch
  118.  
  119.     result = patch_system();
  120.  
  121.  
  122. // put the dialog away; if everything worked, put up an alert saying so
  123.  
  124.     DisposeDialog( dialog );
  125.     if ( result == noErr ) NoteAlert( k_Succeeded_ALRT, nil );
  126. }
  127.  
  128.  
  129. static OSErr patch_system( void )
  130. {
  131.     Boolean destination_created, destination_open;
  132.     Handle h;
  133.     Ptr p;
  134.     short attr;
  135.     FCBPBRec infoPB;
  136.     CMovePBRec movePB;
  137.     HParamBlockRec renamePB;
  138.     Str63 name;
  139.     FSSpec source, destination;
  140.     OSErr result;
  141.     short ref;
  142.  
  143.     destination_created = false;
  144.     destination_open = false;
  145.     h = nil;
  146.     result = noErr;
  147.  
  148.  
  149. // get the location of the system file
  150.  
  151.     infoPB.ioNamePtr = name;
  152.     infoPB.ioFCBIndx = 0;
  153.     infoPB.ioRefNum = 2;
  154.     result = PBGetFCBInfo( &infoPB, false );
  155.     if ( !Success( result == noErr, k_failed_cant_update_disk_error ) ) goto exit;
  156.  
  157.  
  158. // make up FSSpecs for the original and duplicate system files;
  159. // put the duplicate in the root folder with a random name
  160.  
  161.     FSMakeFSSpec( infoPB.ioFCBVRefNum, infoPB.ioFCBParID, infoPB.ioNamePtr, &source );
  162.     NumToString( TickCount(), name );
  163.     FSMakeFSSpec( infoPB.ioFCBVRefNum, 2, name, &destination );
  164.  
  165.  
  166. // duplicate the system file
  167.  
  168.     result = DuplicateFile( &source, &destination );
  169.     if ( !Success( result != dskFulErr, k_failed_cant_update_disk_full ) ) goto exit;
  170.     if ( !Success( result == noErr, k_failed_cant_update_disk_error ) ) goto exit;
  171.     destination_created = true;
  172.  
  173.  
  174. // open up the resource fork of the duplicate
  175.  
  176.     ref = FSpOpenResFile( &destination, fsRdWrPerm );
  177.     result = (ref != -1 ?  noErr : 1);
  178.     if ( !Success( result == noErr, k_failed_cant_update ) ) goto exit;
  179.     destination_open = true;
  180.  
  181.  
  182. // the the resource to patch; it's coming into our heap
  183.  
  184.     h = Get1Resource( 'lpch', 31 );
  185.     result = ResError();
  186.     if ( !Success( result == noErr, k_failed_unknown_system ) ) goto exit;
  187.  
  188.  
  189. // some sanity checks to make sure this is the right system;
  190. // plus a check to see if this system has already been tuned
  191.  
  192.     result = (GetHandleSize( h ) == 254504 ? noErr : 1);
  193.     if ( !Success( result == noErr, k_failed_unknown_system ) ) goto exit;
  194.  
  195.     HLock( h );
  196.     p = *h + 211513;
  197.     result = (*p != 0x2E ? noErr : 1);
  198.     if ( !Success( result == noErr, k_failed_already_tuned ) )  goto exit;
  199.     result = (*p == 0x6E ? noErr : 1);
  200.     if ( !Success( result == noErr, k_failed_unknown_system ) )  goto exit;
  201.  
  202.  
  203. // the patch! all this code for a 1 byte change...
  204.  
  205.     *p = 0x2E;
  206.  
  207.  
  208. // now change the resource info to uncompressed and mark it changed
  209.     attr = GetResAttrs( h );
  210.     result = ResError();
  211.     if ( !Success( result == noErr, k_failed_cant_update ) )  goto exit;
  212.     SetResAttrs( h, attr & ~(mapCompact << 8) );
  213.     result = ResError();
  214.     if ( !Success( result == noErr, k_failed_cant_update ) )  goto exit;
  215.     ChangedResource( h );
  216.     result = ResError();
  217.     if ( !Success( result == noErr, k_failed_cant_update ) )  goto exit;
  218.  
  219.  
  220. // write it back out
  221.  
  222.     UpdateResFile( ref );
  223.     result = ResError();
  224.     if ( !Success( result == noErr, k_failed_cant_update ) )  goto exit;
  225.  
  226.  
  227. // get rid of the resource (to be nice) and close the duplicate file
  228.  
  229.     ReleaseResource( h );
  230.     h = nil;
  231.     CloseResFile( ref );
  232.     result = ResError();
  233.     if ( !Success( result == noErr, k_failed_cant_update ) )  goto exit;
  234.     destination_open = false;
  235.  
  236.  
  237. // now move the original system file into the trash
  238.  
  239.     result = FindFolder( source.vRefNum, kTrashFolderType, kCreateFolder,
  240.             &movePB.ioVRefNum, &movePB.ioNewDirID );
  241.     if ( !Success( result == noErr, k_failed_cant_update ) )  goto exit;
  242.  
  243.     movePB.ioNamePtr = source.name;
  244.     movePB.ioVRefNum = source.vRefNum;
  245.     movePB.ioDirID = source.parID;
  246.     movePB.ioNewName = nil;
  247.  
  248.     result = PBCatMove( &movePB, false );
  249.     if ( !Success( result == noErr, k_failed_cant_update ) )  goto exit;
  250.  
  251.  
  252. // move the patched system file into the system folder (using the original file's location)
  253.  
  254.     movePB.ioNamePtr = destination.name;
  255.     movePB.ioVRefNum = destination.vRefNum;
  256.     movePB.ioDirID = destination.parID;
  257.  
  258.     movePB.ioNewDirID = source.parID;
  259.  
  260.     result = PBCatMove( &movePB, false );
  261.     if ( !Success( result == noErr, k_failed_cant_update_and_system_is_in_trash ) )  goto exit;
  262.  
  263.  
  264. // finally, change the patched system file's name to what the original system file was named
  265.  
  266.     renamePB.fileParam.ioNamePtr = destination.name;
  267.     renamePB.fileParam.ioVRefNum = source.vRefNum;
  268.     renamePB.fileParam.ioDirID = source.parID;
  269.     renamePB.ioParam.ioMisc = (Ptr) source.name;
  270.     result = PBHRename( &renamePB, false );
  271.     if ( !Success( result == noErr, k_failed_cant_update_and_system_has_funny_name ) )  goto exit;
  272.  
  273. exit:
  274.     if ( h ) {
  275.         ReleaseResource( h );
  276.         h = nil;
  277.     }
  278.     if ( destination_open ) {
  279.         CloseResFile( ref );
  280.         destination_open = false;
  281.     }
  282.  
  283.     if ( result && destination_created ) {
  284.         HParamBlockRec deletePB;
  285.  
  286.         deletePB.fileParam.ioNamePtr = (StringPtr) &destination.name;
  287.         deletePB.fileParam.ioVRefNum = destination.vRefNum;
  288.         deletePB.fileParam.ioDirID = destination.parID;
  289.         PBHDelete( &deletePB, false );  // ignore result, since it may've moved
  290.     }
  291.  
  292.     return result;
  293. }
  294.  
  295.  
  296. Boolean Success( Boolean condition, int string_index )
  297. {
  298.     unsigned char *s;
  299.  
  300.     if ( condition ) return true;
  301.  
  302.     assert( string_index > 0 && string_index <= num_strings );
  303.  
  304.     s = strings;
  305.     while ( --string_index ) s += *s + 1;
  306.  
  307.     ParamText( s, nil, nil, nil );
  308.     InitCursor();
  309.     StopAlert( k_Failed_ALRT, nil );
  310.  
  311.     return false;
  312. }
  313.  
  314.  
  315. // a quick and dirty file duplicate routine.
  316.  
  317. // actually, it's pretty good, if I should say so myself. the only area that could
  318. // be improved is the allocation of the temporary duplication buffer.
  319.  
  320. #define kDuplicateFileBufferSize  (200000)
  321.  
  322. static OSErr duplicate_fork( FSSpecPtr source, FSSpecPtr destination, short fork );
  323. static OSErr copy_finfo( FSSpecPtr source, FSSpecPtr destination );
  324.  
  325.  
  326. OSErr DuplicateFile( FSSpecPtr source, FSSpecPtr destination )
  327. {
  328.     OSErr result;
  329.  
  330.     result = noErr;
  331.  
  332.     result = duplicate_fork( source, destination, 0 );
  333.     if ( result ) goto exit;
  334.  
  335.     result = duplicate_fork( source, destination, 1 );
  336.     if ( result ) goto exit;
  337.  
  338.     result = copy_finfo( source, destination );
  339.     if ( result ) goto exit;
  340.  
  341. exit:
  342.     return result;
  343. }
  344.  
  345.  
  346. static OSErr duplicate_fork( FSSpecPtr source, FSSpecPtr destination, short fork )
  347. {
  348.     Boolean source_open, destination_created, destination_open;
  349.     HParamBlockRec sourcePB, destinationPB, flushPB;
  350.     OSErr result;
  351.     Handle buffer_handle;
  352.     Ptr buffer;
  353.  
  354.     source_open = false;
  355.     destination_created = (fork == 1);
  356.     destination_open = false;
  357.     buffer_handle = nil;
  358.     result = noErr;
  359.  
  360.     sourcePB.fileParam.ioNamePtr = (StringPtr) &source->name;
  361.     sourcePB.fileParam.ioVRefNum = source->vRefNum;
  362.     sourcePB.fileParam.ioDirID = source->parID;
  363.  
  364.     sourcePB.ioParam.ioPermssn = fsRdPerm;
  365.     sourcePB.ioParam.ioMisc = nil;
  366.  
  367.     if ( fork == 0 ) result = PBHOpenDF( &sourcePB, false );
  368.     else             result = PBHOpenRF( &sourcePB, false );
  369.     if ( result ) goto exit;
  370.     source_open = true;
  371.  
  372.  
  373.     buffer_handle = TempNewHandle( kDuplicateFileBufferSize, &result );
  374.     if ( result ) goto exit;
  375.     HLock( buffer_handle );
  376.     buffer = *buffer_handle;
  377.  
  378.     destinationPB.fileParam.ioNamePtr = (StringPtr) &destination->name;
  379.     destinationPB.fileParam.ioVRefNum = destination->vRefNum;
  380.     destinationPB.fileParam.ioDirID = destination->parID;
  381.     destinationPB.fileParam.ioFlVersNum = 0;
  382.  
  383.     if ( fork == 0 ) {
  384.         result = PBHCreate( &destinationPB, false );
  385.         if ( result ) goto exit;
  386.         destination_created = true;
  387.     }
  388.  
  389.     destinationPB.ioParam.ioPermssn = fsRdWrPerm;
  390.     destinationPB.ioParam.ioMisc = nil;
  391.  
  392.     if ( fork == 0 ) result = PBHOpenDF( &destinationPB, false );
  393.     else             result = PBHOpenRF( &destinationPB, false );
  394.     if ( result ) goto exit;
  395.     destination_open = true;
  396.  
  397.  
  398.     sourcePB.ioParam.ioBuffer = buffer;
  399.     sourcePB.ioParam.ioPosOffset = 0;
  400.     sourcePB.ioParam.ioPosMode = fsFromStart;
  401.  
  402.     destinationPB.ioParam.ioBuffer = buffer;
  403.     destinationPB.ioParam.ioPosOffset = 0;
  404.     destinationPB.ioParam.ioPosMode = fsFromStart;
  405.  
  406.     for ( ;; ) {
  407.         sourcePB.ioParam.ioReqCount = kDuplicateFileBufferSize;
  408.         result = PBRead( (ParmBlkPtr) &sourcePB, false );
  409.         if ( result == eofErr ) result = noErr;
  410.         if ( result ) goto exit;
  411.  
  412.         if ( sourcePB.ioParam.ioActCount == 0 ) break;
  413.  
  414.         destinationPB.ioParam.ioReqCount = sourcePB.ioParam.ioActCount;
  415.         result = PBWrite( (ParmBlkPtr) &destinationPB, false );
  416.         if ( result ) goto exit;
  417.     }
  418.  
  419.  
  420. exit:
  421.     if ( buffer_handle ) {
  422.         DisposeHandle( buffer_handle );
  423.         buffer_handle = nil;
  424.     }
  425.  
  426.     if ( source_open ) {
  427.         PBClose( (ParmBlkPtr) &sourcePB, false );
  428.         source_open = false;
  429.     }
  430.  
  431.     if ( destination_open ) {
  432.         PBClose( (ParmBlkPtr) &destinationPB, false );
  433.         destination_open = false;
  434.     }
  435.  
  436.     if ( destination_created && result ) {
  437.         destinationPB.fileParam.ioDirID = destination->parID;
  438.         PBHDelete( &destinationPB, false );
  439.         destination_created = false;
  440.     }
  441.  
  442.     flushPB.volumeParam.ioNamePtr = nil;
  443.     flushPB.volumeParam.ioVRefNum = destination->vRefNum;
  444.     PBFlushVol( (ParmBlkPtr) &flushPB, false );    
  445.  
  446.  
  447.     return result;
  448. }
  449.  
  450.  
  451. static OSErr copy_finfo( FSSpecPtr source, FSSpecPtr destination )
  452. {
  453.     CInfoPBRec sourcePB, destinationPB;
  454.     OSErr result;
  455.  
  456.     result = noErr;
  457.  
  458.  
  459.     sourcePB.hFileInfo.ioNamePtr = (StringPtr) &source->name;
  460.     sourcePB.hFileInfo.ioVRefNum = source->vRefNum;
  461.     sourcePB.hFileInfo.ioDirID = source->parID;
  462.  
  463.     sourcePB.hFileInfo.ioFDirIndex = 0;
  464.  
  465.     result = PBGetCatInfo( &sourcePB, false );
  466.     if ( result ) goto exit;
  467.  
  468.  
  469.     destinationPB = sourcePB;
  470.  
  471.     destinationPB.hFileInfo.ioNamePtr = (StringPtr) &destination->name;
  472.     destinationPB.hFileInfo.ioVRefNum = destination->vRefNum;
  473.     destinationPB.hFileInfo.ioDirID = destination->parID;
  474.  
  475.     destinationPB.hFileInfo.ioFDirIndex = 0;
  476.  
  477.     result = PBSetCatInfo( &destinationPB, false );
  478.     if ( result ) goto exit;
  479.  
  480. exit:
  481.     if ( result ) {
  482.         HParamBlockRec deletePB;
  483.  
  484.         deletePB.fileParam.ioNamePtr = (StringPtr) &destination->name;
  485.         deletePB.fileParam.ioVRefNum = destination->vRefNum;
  486.         deletePB.fileParam.ioDirID = destination->parID;
  487.         PBHDelete( &deletePB, false );
  488.     }
  489.  
  490.     return result;
  491. }
  492.